/*
 * Created on Mar 16, 2010
 */
package ro.letsdoitromania;

import java.io.IOException;
import java.util.TimerTask;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDletStateChangeException;
import ro.letsdoitromania.forms.AboutForm;
import ro.letsdoitromania.forms.AddEditForm;
import ro.letsdoitromania.forms.SettingsForm;
import ro.letsdoitromania.forms.ViewList;
import ro.letsdoitromania.forms.LoginForm;
import com.mgmaps.app.APPCommands;
import com.mgmaps.app.ControlKeys;
import com.mgmaps.app.ExtKeyHandler;
import com.mgmaps.app.PendingForm;
import com.mgmaps.gps.GPS;
import com.mgmaps.tools.UITools;
import com.mgmaps.utils.*;

public class LDIRCanvas extends Canvas {
  
  public static LDIRCanvas instance;

  protected final boolean pointerEvents;
  protected int appWidth;
  protected int appHeight;
  protected volatile boolean initialized;

  // images
  protected int titleHeight;
  protected int titleWidth;
  protected int titlePadWidth;
  protected Image splash;
  protected Image title;
  protected Image titlePad;  
  
  public static final int SPLASH_TIMER_INTERVAL = 2500;
  protected int welcomeNumOptions;
  protected Image[] welcomeIcons;
  protected WelcomeScreen welcomeScreen;

  // font
  protected final Font font;
  protected final int fontHeight;
  
  // resize
  protected boolean sizeWasChanged;
  protected int oldw;
  protected int oldh;
  
  public GPS gps;
  private ExtKeyHandler kh;

  public static final int ALERT_TIMEOUT = 3000;
  
  protected class SplashTimerTask extends TimerTask {
    public void run() {
      new Thread(new DummyStarter()).start();
    }
  }
  
  protected class DummyStarter implements Runnable {
    public void run() {
      if (LDIRSettings.isBlackberry && LDIRSettings.featureOnline)
        try {
          final HttpConnection c = (HttpConnection) Connector.open(LDIRSettings.appURL + LDIRSettings.httpExtension);
          c.openInputStream();
          c.getLength();
        } catch (IOException ignore) {
        }
        
      initialize();
    }
  }
  
  /**
   * Called when the screen size changes.
   * @param w new width
   * @param h new height
   * @see javax.microedition.lcdui.Displayable#sizeChanged(int, int)
   */
  protected void sizeChanged(int w, int h) {
    super.sizeChanged(w, h);

    sizeWasChanged = true;
    repaint();
  }
  
  protected void sizeChangedAction(int w, int h) {
    ExtLogger.debug("Size changed to " + w + "x" + h + " (from " + oldw + "x" + oldh + ")");
    
    oldw = w;
    oldh = h;
    
    appWidth = w;
    appHeight = h - titleHeight;

    // set welcome screen size and icons
    if (welcomeScreen != null)
      welcomeScreen.setSize(appWidth, appHeight);
  }
  
  public void setCanvas() {
    Display.getDisplay(LDIRMidlet.instance).setCurrent(this);
  }

  public void initialize() {
    try {
      // initialize downloader, enqueue whatever is needed
      initializeDownloader();
      
      // welcome screen
      final int w = oldw;
      final int h = oldh-titleHeight;
      welcomeScreen = new WelcomeScreen(welcomeScreenOptions(), welcomeIcons, new WelcomePaintArgs(), w, h);
      
      // initialize gps
      if (LDIRSettings.featureGPS)
        gps = new GPS();
      
      kh = new ExtKeyHandler();

      initialized = true;
      splash = null;
      repaint();
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  private void initializeDownloader() {
    // initialize downloader
    // Downloader.defaultHandler = this; 
    LDIRSettings.dl = new com.mgmaps.net.Downloader();
    LDIRSettings.dl.start();
  }
  
  /**
   * Get options for welcome screen.
   * @return string array of options
   */
  private String[] welcomeScreenOptions() {
    return new String[] {
        LS.get("ldir.start.add"),
        LS.get("ldir.start.view"),
        LS.get("ldir.start.send"),
        LS.get("ldir.start.settings"),
        LS.get("ldir.start.about"),
        LS.get("ldir.start.exit")
    };
  }
  
  /**
   * Constructor for LDIRCanvas.
   */
  public LDIRCanvas() {
    super();
    
    instance = this;
    
    // load commands
    APPCommands.initialize();

    oldw = getWidth();
    oldh = getHeight();
    pointerEvents = hasPointerEvents();

    // load images
    try {
      loadImages();
    }
    catch (IOException ie) {
      ExtLogger.handle(ie, true, "Error loading images");
    }
    
    font = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN, Font.SIZE_SMALL);
    fontHeight = font.getHeight();

    // full screen
    if (!LDIRSettings.isBlackberry /* && !LDIRSettings.isNokiaTouch */)
      setFullScreenMode(true);
      
    // splash screen hide timer
    LDIRSettings.timer.schedule(new SplashTimerTask(), SPLASH_TIMER_INTERVAL);
  }
  
  protected void loadImages() throws IOException {
    final int minWH = Math.min(oldw, oldh);
    
    if (minWH < 240)
      splash = Image.createImage("/img/splash1.jpg");
    else
      splash = Image.createImage("/img/splash2.jpg");
    
    final Image titleBig = Image.createImage("/img/title.png");
    if (minWH >= 240) {
      title = UITools.extractImage(titleBig, 160, 0, 0, 45);
      titlePad = UITools.extractImage(titleBig, 16, 10, 0, 45);
    }
    else {
      title = UITools.extractImage(titleBig, ((oldw >= 160) ? 160 : 96), 0, 45, 16);
      titlePad = UITools.extractImage(titleBig, 16, 10, 45, 16);
    }
    titleHeight = title.getHeight();
    titleWidth = title.getWidth();
    titlePadWidth = titlePad.getWidth();

    appWidth = oldw;
    appHeight = oldh - titleHeight;
    
    // welcome
    
    // load image and split into icons
    final Image image = Image.createImage(minWH >= 240 ? LS.get("image.welcome.big") : LS.get("image.welcome.small"));
    final int welcomeNum = welcomeScreenOptions().length;
    welcomeIcons = new Image[welcomeNum];
    for (int i=0; i<welcomeNum; i++)
      welcomeIcons[i] = UITools.extractImage(image, welcomeNum, i);
  }
  
  protected void paint(final Graphics g) {
    try {
      
      // size changed check
      int w = getWidth();
      int h = getHeight();
      
      if (sizeWasChanged) {
        sizeWasChanged = false;
        sizeChangedAction(w, h);
      }
      else if (w != oldw || h != oldh) {
        sizeChangedAction(w, h);
      }
      
      // splash screen
      if (!initialized) {
        if (splash != null) {
          // paint splash
          g.setColor(0xFFFFFFFF);
          g.setClip(0, 0, getWidth(), getHeight());
          g.fillRect(0, 0, getWidth(), getHeight());
          g.drawImage(splash, (getWidth() - splash.getWidth()) / 2,
            (getHeight() - splash.getHeight()) / 2, Graphics.TOP | Graphics.LEFT);
        }
        return;
      }
      
      g.setClip(0, 0, appWidth, titleHeight);
      paintTitleBar(g);

      // HACK always set welcome screen size and icons
      if (welcomeScreen != null)
        welcomeScreen.setSize(w, h-titleHeight);
        
      // welcomeScreen.setSize(getWidth(), getHeight()-titleHeight);
      welcomeScreen.paint(g, 0, titleHeight);
      
    }
    catch (Exception ex) {
      ExtLogger.handle(ex, false, "Exception in paint");
    }
  }
  
  private void paintTitleBar(final Graphics g) {
    // top
    for (int i=0; i<appWidth; i+=titlePadWidth)
      g.drawImage(titlePad, i, 0, Graphics.TOP|Graphics.LEFT);
    g.drawImage(title, (appWidth-titleWidth)/2, 0, Graphics.TOP | Graphics.LEFT);
  }
  
  protected void notifyExit() {
    if (gps != null)
      gps.notifyExit();
  }

  /**
   * Called when GPS position is updated.
   */
  public void notifyGPSUpdate(boolean force) {
    repaint();
  }
  
  public void showAlert(String string) {
    showAlert(string, string, ALERT_TIMEOUT);
  }

  /**
   * Show an alert form for a few seconds.
   * @param alertMessage alert text
   */
  public void showAlert(String alertTitle, String alertMessage, int timeout) {
    final Alert alert = new Alert(alertTitle, alertMessage, null, AlertType.INFO);
    alert.setTimeout(timeout);
    Display.getDisplay(LDIRMidlet.instance).setCurrent(alert);
  }
  
  private void welcomeScreenAction(int selected) {
    try {
      switch (selected) {
        case 0:
          actionAdd();
          break;
        case 1:
          actionView();
          break;
        case 2:
          actionSend();
          break;
        case 3:
          actionSettings();
          break;
        case 4:
          actionAbout();
          break;
        case 5:
          actionExit();
          break;
      }
    }
    catch (Exception ex) {
      ExtLogger.handle(ex, false, "Error");
    }
  }
  
  private void actionAdd() {
    AddEditForm.getInstance().showAdd();
  }
  
  private void actionView() {
    if (LDIRSettings.points.size() == 0)
      showAlert(LS.get("ldir.viewlist.title"), LS.get("ldir.viewlist.nopoints"), ALERT_TIMEOUT);
    else
      ViewList.getInstance().show();
  }
  
  private void actionSend() {
    if (LDIRSettings.points.size() == 0)
      showAlert(LS.get("ldir.upload.title"), LS.get("ldir.upload.nopoints"), ALERT_TIMEOUT);
    else if (LDIRSettings.username.length() == 0 || LDIRSettings.password.length() == 0)
      LoginForm.getInstance().show();
    else
      startUpload();
  }
  
  private void actionSettings() {
    SettingsForm.getInstance().show();
  }
  
  private void actionAbout() {
    AboutForm.getInstance().show();
  }
  
  public void actionExit() {
    try {
      LDIRMidlet.instance.destroyApp(true);
    }
    catch (MIDletStateChangeException ignore) {}
  }
  
  public void startUpload() {
    PendingForm.getInstance().show(this, LS.get("ldir.upload.title"), LS.get("ldir.upload.pending"));
    // auth request if salt is not set
    if (LDIRSettings.usersalt.length() == 0)
      LDIRSettings.dl.enqueue(new AuthSaltRequest());
    else
      LDIRSettings.dl.enqueue(new TrashPointRequest());
  }
  
  protected void keyPressed(int keyCode) {
    if (!initialized)
      return;
    
    final int action = kh.getKeyActionCode(keyCode);
    
    if (action == ControlKeys.MOVE_LEFT_KEY) {
      welcomeScreen.keyLeft();
      repaint();
    }
    else if (action == ControlKeys.MOVE_RIGHT_KEY) {
      welcomeScreen.keyRight();
      repaint();
    }
    else if (action == ControlKeys.MOVE_DOWN_KEY) {
      welcomeScreen.keyDown();
      repaint();
    }
    else if (action == ControlKeys.MOVE_UP_KEY) {
      welcomeScreen.keyUp();
      repaint();
    }
    else if (action == ControlKeys.SELECT_KEY)
      welcomeScreenAction(welcomeScreen.getSelectedIndex());
  }

  protected void keyRepeated(int keyCode) {
    if (!initialized)
      return;

    final int action = kh.getKeyActionCode(keyCode);

    if (action == ControlKeys.MOVE_LEFT_KEY || action == ControlKeys.MOVE_RIGHT_KEY ||
        action == ControlKeys.MOVE_UP_KEY || action == ControlKeys.MOVE_DOWN_KEY)
      keyPressed(keyCode);
  }
  
  protected void keyReleased(int keyCode) {
    if (!initialized)
      return;
    
    // show log
    if (LDIRSettings.LOG_AVAILABLE && keyCode == KEY_NUM8)
      Display.getDisplay(LDIRMidlet.instance).setCurrent(new LogForm(LDIRMidlet.instance, this));
  }

  protected void pointerPressed(int x, int y) {
    if (!initialized)
      return;
        
    // this selects the option
    welcomeScreen.getClickedOption(x, y-titleHeight);
    repaint();
  }

  protected void pointerReleased(int x, int y) {
    if (!initialized)
      return;
    
    final int option = welcomeScreen.getClickedOption(x, y-titleHeight);
    repaint();
    if (option >= 0)
      welcomeScreenAction(option);
  }

  protected void pointerDragged(int x, int y) {
    if (!initialized)
      return;
    
    // this selects the option
    welcomeScreen.getClickedOption(x, y-titleHeight);
    repaint();
  }

  /**
   * Set new language items.
   */
  public void loadNewLanguage() {
    welcomeScreen.setOptions(welcomeScreenOptions());
    APPCommands.initialize();
  }
}
